package com.sigmatrix.h5.service.drawcash;

import java.math.BigDecimal;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.sigmatrix.h5.auth.ILoginUser;
import com.sigmatrix.h5.components.FeignManager;
import com.sigmatrix.h5.dao.DisRebateDetailDao;
import com.sigmatrix.h5.dao.EnterpriseDao;
import com.sigmatrix.h5.entity.DisRebateDetail;
import com.sigmatrix.h5.entity.Enterprise;
import com.sigmatrix.h5.entity.v2.DisDealerAcct;
import com.sigmatrix.h5.enums.CrmAcctType;
import com.sigmatrix.h5.enums.RebateTarget;
import com.sigmatrix.h5.enums.WalletType;
import com.sigmatrix.h5.exception.MessageException;
import com.sigmatrix.h5.feign.args.WechatRedPacketDto;
import com.sigmatrix.h5.feign.mode.CoinDto;
import com.sigmatrix.h5.feign.mode.WechatRedPacketSendingResponse;
import com.sigmatrix.h5.redisson.DistributedLocker;
import com.sigmatrix.h5.redisson.LockedWorker;
import com.sigmatrix.h5.service.db.DisDealerAcctDBService;
import com.sigmatrix.h5.service.db.DisRebateDetailDBService;
import com.sigmatrix.h5.utils.Assert;
import com.sigmatrix.h5.utils.CommonUtils;
import com.sigmatrix.h5.utils.Constants;
import com.sigmatrix.h5.web.args.DrawCashParam;

@Service
public class DefaultDrawCashHandler implements IDrawCash{

	private static Logger logger = LoggerFactory.getLogger(DefaultDrawCashHandler.class);
	
	@Autowired
	private DistributedLocker redissonLocker; 
	
	@Autowired
	private DisDealerAcctDBService disDealerAcctDBService; 

	@Autowired
	private DisRebateDetailDBService disRebateDetailDBService;
	
	@Autowired
	private EnterpriseDao enterpriseDao; 
	
	@Autowired
	private FeignManager feignClientManager;
	
	@Autowired
	private DisRebateDetailDao disRebateDetailDao;
	
	@Override
	@Transactional
	public IRedPackReceipt sendWeChatRedPack(ILoginUser user, DrawCashParam param) {
		
			if(CommonUtils.isEmpty(param.getAmount())){
				throw new MessageException("提现金额不能为空");
			}
			
			DisDealerAcct disDealerAcct = disDealerAcctDBService.selectById(user.getAcctId(), null);
			
			if(CommonUtils.isEmpty(user)){
				throw new MessageException("用户不存在或不可用");
			}
			if(!disDealerAcct.isEnabled()){
				throw new MessageException("用户不存在或不可用");				
			}
			if(!disDealerAcct.getOpenId().equals(user.getOpenId())){
				throw new MessageException("您的账号已在其他地方登录,请重新登录");				
			}
			if(CommonUtils.isEmpty(user.getEseId())){
				throw new MessageException("无效的账号，没有关联企业");				
			}
			Enterprise enterprise = enterpriseDao.findById(user.getEseId());
			if(CommonUtils.isEmpty(enterprise)){
				throw new MessageException("没有查询到企业");	
			}
			CoinDto coin = feignClientManager.findCoin(enterprise.getBasicModuleId());
			if(CommonUtils.isEmpty(coin)){
				throw new MessageException("没有查询到红包参数");	
			}
			//单位转换，在返利系统单位是元，营销系单位是分
			BigDecimal amount = param.getAmount().multiply(new BigDecimal(100));
			if(amount.compareTo(new BigDecimal(coin.getMaxAmount())) > 0){
				throw new MessageException("提现金额超出上限["+coin.getMaxAmount().doubleValue()/100+"元]");	
			}
			if(amount.compareTo(new BigDecimal(coin.getMinAmount())) < 0){
				throw new MessageException("提现金额没有达到下限["+coin.getMinAmount().doubleValue()/100+"元]");	
			}
			
			Integer cardHolder = null;
			Short dealerType = null;
			if(CrmAcctType.isDealerAcct(user.getAcctType())){//经销商类型账户
				if(WalletType.isPersonalWallet(param.getWalletType())){
					cardHolder = user.getAcctId();	
					dealerType = RebateTarget.SALES_MAN.value;
				}else if(WalletType.isEntWallet(param.getWalletType())){
					cardHolder = user.getDealerOrShopId();
					dealerType = RebateTarget.DEALER.value;
				}else{
					throw new MessageException("未指定零钱包类型。");
				}
			}else if(CrmAcctType.isShopAcct(user.getAcctType())){//终端店类型账户
				cardHolder = user.getDealerOrShopId();
				dealerType = RebateTarget.TERMINAL_SHOP.value;
			}else if(CrmAcctType.isEseAcct(user.getAcctType())){//企业下账户
				cardHolder = user.getAcctId();
				dealerType = RebateTarget.SALES_MAN.value;
			}
			
			if(cardHolder==null){
				throw new MessageException("系统错误");
			}
			
			boolean available = redissonLocker.isAvailable(disDealerAcct.getOpenId());
			if(!available){
				throw new MessageException("提现正在操作。。");
			}
			
			BigDecimal total = disRebateDetailDBService.statAmountsByDealerIdAndType(user.getEseCode(), cardHolder, Integer.valueOf(dealerType));
			if(total == null || amount.compareTo(total.multiply(new BigDecimal(100))) > 0){
				throw new MessageException("账户余额不足");
			}
			
			final Integer dealerId = cardHolder;
			
			final Short dealerTypeFinal = dealerType;
			
			LockedWorker<IRedPackReceipt> worker = new LockedWorker<IRedPackReceipt>() {

				@Override
				public IRedPackReceipt invokeAfterLocked() {
					//先记账再发红包，如果发送红包失败，抛出异常，事务回滚
					DisRebateDetail rebateDetail = new DisRebateDetail();
					rebateDetail.setApplicantName(user.getLoginName());
					rebateDetail.setCellphoneNum(user.getPhoneNumber());
					rebateDetail.setDealerId(dealerId);
					rebateDetail.setRebateAmount(amount.multiply(new BigDecimal(-0.01)).setScale(2, BigDecimal.ROUND_HALF_UP));//取现金额为负数
					rebateDetail.setRebateType(Constants.REBATE_TYPE_IMMEDIATE);
					rebateDetail.setDrawCashUserId(user.getAcctId());
					rebateDetail.setDrawCashOpenId(disDealerAcct.getOpenId());
					rebateDetail.setRebateTime(new Date());
					rebateDetail.setDealerType(dealerTypeFinal);
					Integer detailId = disRebateDetailDao.insertSelective(rebateDetail);
					Assert.notNull(detailId, "更新零钱包失败");
					//发红包
					WechatRedPacketDto redPacket = new WechatRedPacketDto();
					redPacket.setAppId(coin.getToAppId());//公众号ID
					redPacket.setOpenId(disDealerAcct.getOpenId());//用户openId
					redPacket.setRedPacketId((long)coin.getRedPacketId());//红包参数ID
					redPacket.setTotalAmount(amount.intValue());//金额
					redPacket.setTotalNum(1);//红包总数
					redPacket.setWechatRedPacketType(Constants.RED_PACKET_TYPE_COMMON);//
					WechatRedPacketSendingResponse response;
					
					try {
						response = feignClientManager.sendRedPacket(redPacket);
					} catch (Exception e) {
						throw new MessageException("红包发送失败。",e);
					}
					
					if(CommonUtils.isNotEmpty(response) && "SUCCESS".equals(response.getResultCode())){
						//只能先保存再更新，否则发送红包以后，保存失败，不能退回红包
						rebateDetail = new DisRebateDetail(); 
						rebateDetail.setMerchantBillNo(response.getMerchantBillNo());
						rebateDetail.setMerchantId(response.getMerchantId());
						rebateDetail.setId(detailId);
						disRebateDetailDao.updateSelective(rebateDetail);
					}else{
						logger.error("发送红包参数：openId："+redPacket.getOpenId()+"，金额："+amount.longValue());
						throw new MessageException(response.getErrCodeDes());
					}
					return response;
				}
			};
			
			return redissonLocker.lockAndInvoke(disDealerAcct.getOpenId(), worker, 1000);
		}



}
